package com.h3bpm.web.login;

/**
 * @Author: VillWang
 * @Date: 2020/6/1 15:10
 */


import OThinker.Common.Clusterware.Connection.ConnectionResult;
import OThinker.Common.Clusterware.LogicUnits.AuthenticationType;
import OThinker.Common.Data.Database.Parameter;
import OThinker.Common.Data.DbType;
import OThinker.Common.DotNetToJavaStringHelper;
import OThinker.Common.Organization.Interface.IOrganization;
import OThinker.Common.Organization.Models.User;
import OThinker.Common.Organization.enums.State;
import OThinker.Common.Organization.enums.UserServiceState;
import OThinker.Common.RefObject;
import OThinker.Common.util.ListUtil;
import OThinker.H3.Entity.Configs.LicenseType;
import OThinker.H3.Entity.ConnectionStringParser.ConnectionMode;
import OThinker.H3.Entity.IEngine;
import OThinker.H3.Entity.Notification.DingTalk.DingTalkUserByUserId;
import OThinker.H3.Entity.Notification.DingTalk.DingTalkUserInfo;
import OThinker.H3.Entity.Site.PortalType;
import com.h3bpm.base.engine.connection.Connection;
import com.h3bpm.base.engine.connection.EngineConnectionUtil;
import com.h3bpm.base.user.AuthenticationMode;
import com.h3bpm.base.user.UserValidator;
import com.h3bpm.base.user.UserValidatorHolder;
import com.h3bpm.base.util.AppConfig;
import com.h3bpm.base.util.AppUtility;
import com.h3bpm.base.util.Sessions;
import com.h3bpm.base.util.SheetUtility;
import com.h3bpm.web.util.AESUtil;
import data.DataRow;
import data.DataTable;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URLDecoder;
import java.util.*;

public class UserFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(com.h3bpm.base.user.UserValidatorFactory.class);

    public UserFactory() {
    }

    public static UserValidator Validate(HttpServletRequest request, HttpServletResponse response, String userAlias, String password) throws Exception {
        if (EngineConnectionUtil.getConnectionMode() == ConnectionMode.Mono) {
            boolean enableAD = false;
            boolean success = false;
            String adPath = "";
            Map<String, Object> settings = AppUtility.getEngine().getSettingManager().GetSheetSettings();
            enableAD = (Boolean)settings.get("EnableADValidation");
            adPath = settings.get("ADPathes") + "";
            success = Validate(EngineConnectionUtil.getMonoEngine().getOrganization(), userAlias, password, enableAD, adPath);
            if (!success) {
                return null;
            } else {
                UserValidator user = GetUserValidator(request, EngineConnectionUtil.getMonoEngine(), userAlias, settings);
                if (!LicenseType.Develop.toString().equals(user.getPortalSettings(request).get("LicenseType") + "") && !Boolean.parseBoolean(user.getPortalSettings(request).get("Mobile") + "") && request != null) {
                    String url = request.getRequestURI().toLowerCase();
                    if (url.indexOf("mobile") > -1 || url.indexOf("ismobile") > -1) {
                        return null;
                    }
                }

                return user;
            }
        } else if (!Login(request, AuthenticationType.Forms, (String)null, userAlias, password, false)) {
            return null;
        } else {
            Map<String, Object> settings = getCurrentUser(request, response).getEngine().getSettingManager().GetSheetSettings();
            if (!Boolean.parseBoolean(settings.get("Mobile") + "") && request != null) {
                String url = request.getRequestURI().toLowerCase();
                if (url.indexOf("mobile") > -1 || url.indexOf("ismobile") > -1) {
                    return null;
                }
            }

            return getCurrentUser(request, response);
        }
    }

    public static UserValidator GetUserValidator(HttpServletRequest request, IEngine Engine, String UserLoginName) throws Exception {
        return GetUserValidator(request, Engine, UserLoginName, EngineConnectionUtil.getMonoPortalSettings());
    }

    public static UserValidator GetUserValidator(HttpServletRequest request, IEngine Engine, String UserLoginName, Map<String, Object> Settings) throws Exception {
        if (DotNetToJavaStringHelper.isNullOrEmpty(UserLoginName)) {
            return null;
        } else {
            String tempImagesPath = System.getProperty("user.dir") + "TempImages";
            User unit = Engine.getOrganization().GetUserByCode(UserLoginName);
            return unit == null ? null : new UserValidator(request, Engine, unit.getObjectID(), tempImagesPath, Settings);
        }
    }

    private static UserValidator GetUserValidator(HttpServletRequest request, IEngine Engine, String TempImagesPath, String UserLoginName, Map<String, Object> PortalSettings) throws Exception {
        if (DotNetToJavaStringHelper.isNullOrEmpty(UserLoginName)) {
            return null;
        } else {
            User unit = Engine.getOrganization().GetUserByCode(UserLoginName);
            return unit == null ? null : new UserValidator(request, Engine, unit.getObjectID(), TempImagesPath, PortalSettings);
        }
    }

    public static UserValidator GetUserValidator(IEngine Engine, String TempImagesPath, String UserLoginName, Map<String, Object> PortalSettings) throws Exception {
        if (DotNetToJavaStringHelper.isNullOrEmpty(UserLoginName)) {
            return null;
        } else {
            User unit = Engine.getOrganization().GetUserByCode(UserLoginName);
            return unit == null ? null : new UserValidator(Engine, unit.getObjectID(), TempImagesPath, PortalSettings);
        }
    }

    public static UserValidator GetUserValidatorById(HttpServletRequest request, IEngine Engine, String TempImagesPath, String UserId, Map<String, Object> PortalSettings) throws Exception {
        return UserId != null && !UserId.equals("") && null != Engine.getOrganization().GetUnit(UserId) ? new UserValidator(request, Engine, UserId, TempImagesPath, PortalSettings) : null;
    }

    public static void RedirectLogin(HttpServletRequest Request, HttpServletResponse Response, String PortalRoot) throws Exception {
        if (Request.getRequestURI().toLowerCase().indexOf((PortalRoot + "/Admin").toLowerCase()) <= -1) {
            if (!Request.getRequestURI().toLowerCase().contains("login.jsp") && !Request.getRequestURI().toLowerCase().contains("mvcdefaultsheet.jsp")) {
                String loginParam = "q=" + URLDecoder.decode(Request.getRequestURI());
                String loginUrl = (AppConfig.getPortalRootForUrl() + "/index.html").replaceAll("\\\\", "/") + "?" + loginParam;
                Response.sendRedirect(loginUrl);
            }
        }
    }

    public static UserValidator LoginAsWeChatReturnUserValidator(HttpServletRequest request, String EngineCode, String WeChatCode) throws Exception {
        UserValidator user = null;
        String userCode = "";
        String tempImagesPath = System.getProperty("user.dir") + "/TempImages";
        String clientPlatform;
        switch(EngineConnectionUtil.getConnectionMode()) {
            case Mono:
                IEngine engine = AppUtility.getEngine();
                userCode = engine.getWeChatAdapter().GetUserCode(WeChatCode);
                LOGGER.info("微信userCode: " + userCode);
                User unit = engine.getOrganization().GetUserByCode(userCode);
                LOGGER.info("微信userUnit: " + unit);
                if (unit == null && StringUtils.isNotBlank(userCode)) {
                    try {
                        LOGGER.info("校验其他信息 -> " + userCode);
                        clientPlatform = "select Code from OT_User where WeChatAccount=? or Email=? or Mobile=?";
                        List<Parameter> params = new ArrayList();
                        params.add(new Parameter("WeChatAccount", DbType.String, userCode));
                        params.add(new Parameter("Email", DbType.String, userCode));
                        params.add(new Parameter("Mobile", DbType.String, userCode));
                        DataTable dt = AppUtility.getPortalQuery().QueryTable(clientPlatform, (Parameter[])ListUtil.toArray(params));
                        if (dt != null && dt.getRows().size() > 0) {
                            DataRow row = dt.getRows().get(0);
                            String ucode = row.getString("code");
                            unit = engine.getOrganization().GetUserByCode(ucode);
                            LOGGER.info("获取微信对应的账号 {}->{}", userCode, ucode);
                        }
                    } catch (Exception var13) {
                        LOGGER.error("Login by wechat error, {}", var13.getMessage());
                    }
                }

                if (unit == null) {
                    LOGGER.info("【X】微信登陆的账号 {} 没有匹配的用户", userCode);
                    return null;
                }

                if (unit.getServiceState() != UserServiceState.Dismissed && !unit.getIsVirtualUser() && unit.getState() != State.Inactive) {
                    if (!userCode.equals(unit.getWeChatAccount())) {
                        unit.setWeChatAccount(userCode);
                        unit.setModifiedTime(new Date());
                        engine.getOrganization().UpdateUnit("18f923a7-5a5e-426d-94ae-a55ad1a4b239", unit);
                        LOGGER.info("【U】更新账号绑定到微信的账号 {}->{}", unit.getCode(), userCode);
                    }

                    user = new UserValidator(request, engine, unit.getObjectID(), tempImagesPath, (Map)null);
                    break;
                }

                LOGGER.info("【X】微信登陆的账号 {}->{} 是已离职/已禁用/虚拟用户", userCode, unit.getCode());
                return null;
            case Shared:
                Connection conn = new Connection();
                String userId = "";
                RefObject<String> tempRef_userId = new RefObject(userId);
                boolean tempVar = conn.Open(EngineConnectionUtil.getConnectionStringParser().getServers()[0], AuthenticationType.WeChat, EngineCode, WeChatCode, "WeChat", tempRef_userId) != ConnectionResult.Success;
                userId = (String)tempRef_userId.argvalue;
                if (tempVar) {
                    return null;
                }

                user = new UserValidator(request, conn.getEngine(), userId, tempImagesPath, (Map)null);
                break;
            default:
                throw new NotImplementedException();
        }

        String clientIP = SheetUtility.GetClientIP(request);
        String clientBrowser = SheetUtility.GetClientBrowser(request);
        clientPlatform = SheetUtility.GetClientPlatform(request);
        AppUtility.OnUserLogin(user, PortalType.WeChat, clientIP, clientBrowser, clientPlatform);
        return user;
    }

    public static boolean LoginAsWeChat(HttpServletRequest request, String EngineCode, String WeChatCode) throws Exception {
        UserValidator user = LoginAsWeChatReturnUserValidator(request, EngineCode, WeChatCode);
        if (user == null) {
            return false;
        } else {
            request.getSession().setAttribute(Sessions.GetWeChatLogin(), true);
            request.getSession().setAttribute(Sessions.GetUserValidator(), user);
            String clientIP = SheetUtility.GetClientIP(request);
            String clientBrowser = SheetUtility.GetClientBrowser(request);
            String clientPlatform = SheetUtility.GetClientPlatform(request);
            AppUtility.OnUserLogin(user, PortalType.WeChat, clientIP, clientBrowser, clientPlatform);
            return true;
        }
    }

    public static UserValidator LoginAsDingTalkReturnUserValidator(HttpServletRequest request, String EngineCode, String DingTalkCode) throws Exception {
        LOGGER.info("授权码，JSAPI获取");
        UserValidator user = null;
        String userCode = "";
        String tempImagesPath = System.getProperty("user.dir") + "/TempImages";
        String uCode;
        switch(EngineConnectionUtil.getConnectionMode()) {
            case Mono:
                LOGGER.info("Mono");
                IEngine engine = AppUtility.getEngine();
               // userCode = AESUtil.decrypt(DingTalkCode);
                userCode=DingTalkCode;
                if (!StringUtils.isNotBlank(userCode)) {
                    LOGGER.info("获取钉钉用户信息: " + userCode);
                    return null;
                }

                LOGGER.info("userCode==" + userCode);
                User unit = engine.getOrganization().GetUserByCode(userCode);
                if (unit == null) {
                    DingTalkUserByUserId dingTalkUserInfo = engine.getDingTalkAdapter().GetUserInfoByUserid(userCode);
                    if (dingTalkUserInfo != null) {
                        LOGGER.info("========DingTalkUserInfo=======" + dingTalkUserInfo.getName());
                        uCode = engine.getOrganization().GetUserCodeByMobile(dingTalkUserInfo.getMobile());
                        LOGGER.info("==========uCode.uCode()=========" + uCode);
                        unit = engine.getOrganization().GetUserByCode(uCode);
                        LOGGER.info("unit.unit()" + unit);
                    }
                }

                if (unit != null && unit.getServiceState() != UserServiceState.Dismissed && !unit.getIsVirtualUser() && unit.getState() != State.Inactive) {
                    if (DotNetToJavaStringHelper.isNullOrEmpty(unit.getDingTalkAccount())) {
                        LOGGER.info("DingTalkAccount为空时做一次更新");
                        unit.setDingTalkAccount(userCode);
                        engine.getOrganization().UpdateUnit("18f923a7-5a5e-426d-94ae-a55ad1a4b239", unit);
                    }

                    user = new UserValidator(request, engine, unit.getObjectID(), tempImagesPath, (Map)null);
                    LOGGER.info("user:" + user.getUserName());
                    break;
                }

                return null;
            case Shared:
                Connection conn = new Connection();
                uCode = "";
                RefObject<String> tempRef_userId = new RefObject(uCode);
                boolean tempVar = conn.Open(EngineConnectionUtil.getConnectionStringParser().getServers()[0], AuthenticationType.WeChat, EngineCode, DingTalkCode, "DingTalk", tempRef_userId) != ConnectionResult.Success;
                uCode = (String)tempRef_userId.argvalue;
                if (tempVar) {
                    return null;
                }

                user = new UserValidator(request, conn.getEngine(), uCode, tempImagesPath, (Map)null);
                break;
            default:
                throw new NotImplementedException();
        }

        String clientIP = SheetUtility.GetClientIP(request);
        String clientBrowser = SheetUtility.GetClientBrowser(request);
        String clientPlatform = SheetUtility.GetClientPlatform(request);
        AppUtility.OnUserLogin(user, PortalType.DingTalk, clientIP, clientBrowser, clientPlatform);
        return user;
    }

    public static boolean LoginAsDingTalk(HttpServletRequest request, String EngineCode, String DingTalkCode) throws Exception {
        UserValidator user = LoginAsDingTalkReturnUserValidator(request, EngineCode, DingTalkCode);
        if (user == null) {
            return false;
        } else {
            request.getSession().setAttribute(Sessions.GetDingTalkLogin(), true);
            request.getSession().setAttribute(Sessions.GetUserValidator(), user);
            String clientIP = SheetUtility.GetClientIP(request);
            String clientBrowser = SheetUtility.GetClientBrowser(request);
            String clientPlatform = SheetUtility.GetClientPlatform(request);
            AppUtility.OnUserLogin(user, PortalType.DingTalk, clientIP, clientBrowser, clientPlatform);
            return true;
        }
    }

    public static UserValidator LoginAsDingTalkPCAndReturnUserValidator(HttpServletRequest request, String EngineCode, String UserID) throws Exception {
        UserValidator user = null;
        String userCode = "";
        String tempImagesPath = System.getProperty("user.dir") + "/TempImages";
        String uCode;
        switch(EngineConnectionUtil.getConnectionMode()) {
            case Mono:
                IEngine engine = AppUtility.getEngine();
                DingTalkUserInfo dingUser = engine.getDingTalkAdapter().GetUserInfo(UserID);
                if (dingUser == null) {
                    LOGGER.info("获取钉钉用户信息: " + dingUser);
                    return null;
                }

                userCode = dingUser.getUserid();
                LOGGER.info("userCode: " + userCode);
                User unit = engine.getOrganization().GetUserByCode(userCode);
                if (unit == null) {
                    DingTalkUserByUserId dingTalkUserInfo = engine.getDingTalkAdapter().GetUserInfoByUserid(userCode);
                    if (dingTalkUserInfo != null) {
                        LOGGER.info("DingTalkUserInfo: " + dingTalkUserInfo.getName());
                        uCode = engine.getOrganization().GetUserCodeByMobile(dingTalkUserInfo.getMobile());
                        LOGGER.info("uCode: " + uCode);
                        unit = engine.getOrganization().GetUserByCode(uCode);
                        LOGGER.info("unit: " + unit);
                    }
                }

                if (unit != null && unit.getServiceState() != UserServiceState.Dismissed && !unit.getIsVirtualUser()) {
                    user = new UserValidator(request, engine, unit.getObjectID(), tempImagesPath, (Map)null);
                    break;
                }

                return null;
            case Shared:
                Connection conn = new Connection();
                uCode = "";
                RefObject<String> tempRef_userId = new RefObject(uCode);
                boolean tempVar = conn.Open(EngineConnectionUtil.getConnectionStringParser().getServers()[0], AuthenticationType.WeChat, EngineCode, UserID, "DingTalk") != ConnectionResult.Success;
                uCode = (String)tempRef_userId.argvalue;
                if (tempVar) {
                    return null;
                }

                user = new UserValidator(request, conn.getEngine(), uCode, tempImagesPath, (Map)null);
                break;
            default:
                throw new NotImplementedException();
        }

        String clientIP = SheetUtility.GetClientIP(request);
        String clientBrowser = SheetUtility.GetClientBrowser(request);
        String clientPlatform = SheetUtility.GetClientPlatform(request);
        AppUtility.OnUserLogin(user, PortalType.DingTalk, clientIP, clientBrowser, clientPlatform);
        return user;
    }

    public static boolean Login(HttpServletRequest request, AuthenticationType AuthenticationType, String EngineCode, String UserName, String Password) throws Exception {
        return Login(request, AuthenticationType, EngineCode, UserName, Password, false);
    }

    public static boolean Login(HttpServletRequest request, AuthenticationType AuthenticationType, String EngineCode, String UserName, String Password, boolean isAdminLogin) throws Exception {
        String tempImagesPath = System.getProperty("user.dir") + File.separator + "TempImages";
        UserValidator user;
        switch(EngineConnectionUtil.getConnectionMode()) {
            case Mono:
                IEngine engine = AppUtility.getEngine();
                Map<String, Object> settings = engine.getSettingManager().GetSheetSettings();
                boolean enableAD = Boolean.valueOf(String.valueOf(settings.get("EnableADValidation")));
                String adPath = String.valueOf(settings.get("ADPathes"));
                if (!Validate(engine.getOrganization(), UserName, Password, enableAD, adPath)) {
                    return false;
                }

                user = GetUserValidator(request, engine, tempImagesPath, UserName, settings);
                break;
            case Shared:
                Connection conn = new Connection();
                if (conn.Open(EngineConnectionUtil.getConnectionStringParser().getServers()[0], AuthenticationType, EngineCode, UserName, Password) != ConnectionResult.Success) {
                    return false;
                }

                User unit = conn.getEngine().getOrganization().GetUserByCode(UserName);
                if (unit == null) {
                    return false;
                }

                user = new UserValidator(request, conn.getEngine(), unit.getUnitID(), tempImagesPath, (Map)null);
                break;
            default:
                throw new NotImplementedException();
        }

        if (user == null) {
            return false;
        } else if (isAdminLogin && !user.getUser().getIsConsoleUser() && !user.ValidateAdministrator()) {
            return false;
        } else {
            request.getSession().setAttribute(Sessions.GetUserValidator(), user);
            UserValidatorHolder.set(user);
            String clientIP = SheetUtility.GetClientIP(request);
            String clientBrowser = SheetUtility.GetClientBrowser(request);
            String clientPlatform = SheetUtility.GetClientPlatform(request);
            AppUtility.OnUserLogin(user, isAdminLogin ? PortalType.AdminPortal : PortalType.UserPortal, clientIP, clientBrowser, clientPlatform);
            return true;
        }
    }

    public static UserValidator getCurrentUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (request != null && request.getSession() != null && request.getSession().getAttribute(Sessions.GetUserValidator()) == null) {
            switch(EngineConnectionUtil.getConnectionMode()) {
                case Mono:
                    String urlAlias = request.getParameter("LoginName") != null ? request.getParameter("LoginName") : request.getAttribute("LoginName") + "";
                    urlAlias = URLDecoder.decode(urlAlias);
                    if (DotNetToJavaStringHelper.isNullOrEmpty(urlAlias)) {
                        return null;
                    }

                    String loginPassword = request.getParameter("LoginPassword") != null ? request.getParameter("LoginPassword") : request.getAttribute("LoginPassword") + "";
                    loginPassword = URLDecoder.decode(loginPassword);
                    if (!Login(request, AuthenticationType.Forms, (String)null, urlAlias, loginPassword)) {
                        RedirectLogin(request, response, AppConfig.getPortalRoot());
                    }

                    request.getSession().setAttribute(Sessions.GetUserValidator(), getCurrentUser(request, response));
                    break;
                case Shared:
                    RedirectLogin(request, response, AppConfig.getPortalRoot());
            }
        }

        return request != null && request.getSession() != null ? (UserValidator)request.getSession().getAttribute(Sessions.GetUserValidator()) : null;
    }

    public static void Redirect(HttpServletRequest request, HttpServletResponse response, String userName) throws Exception {
        AuthenticationMode authMode = AppConfig.getAuthenticationMode();
        if (authMode != AuthenticationMode.Forms) {
            String goUrl = request.getParameter("ReturnUrl") != null ? request.getParameter("ReturnUrl") : request.getAttribute("ReturnUrl") + "";
            if (goUrl == null || goUrl.isEmpty()) {
                goUrl = request.getParameter("q") != null ? request.getParameter("q") : request.getAttribute("q") + "";
            }

            if (DotNetToJavaStringHelper.isNullOrEmpty(goUrl)) {
                goUrl = request.getSession().getServletContext().getRealPath("/");
                if (!goUrl.endsWith("/")) {
                    goUrl = goUrl + "/";
                }
            }

            response.sendRedirect(goUrl);
        }

    }

    public static boolean Validate(IOrganization Organization, String UserAlias, String Password, boolean EnableADValidation, String ADPathes) throws Exception {
        return ValidateUser(Organization, UserAlias, Password, EnableADValidation, ADPathes) != null;
    }

    public static User ValidateUser(IOrganization Organization, String UserAlias, String Password, boolean EnableADValidation, String ADPathes) throws Exception {
        if (UserAlias == null) {
            return null;
        } else {
            User user = Organization.GetUserByCode(UserAlias);
            if (user != null && user.getState() != State.Inactive && !user.getIsVirtualUser() && user.getServiceState() != UserServiceState.Dismissed) {
                if (!EnableADValidation || user.getIsSystemUser() && user.getIsAdministrator()) {
                    if (user.validatePassword(Password)) {
                        return user;
                    }
                } else {
                    boolean success = false;
                    if (!DotNetToJavaStringHelper.isNullOrEmpty(ADPathes)) {
                        String[] ads = ADPathes.split(";");
                        String[] var8 = ads;
                        int var9 = ads.length;

                        for(int var10 = 0; var10 < var9; ++var10) {
                            String ad = var8[var10];
                            if (!ad.isEmpty()) {
                                success = IsAuthenticated(ad, UserAlias, Password);
                                if (success) {
                                    return user;
                                }
                            }
                        }
                    }
                }

                return null;
            } else {
                return null;
            }
        }
    }

    private static boolean IsAuthenticated(String AdServer, String UserName, String Password) {
        DirContext dirContext = null;
        Hashtable<String, String> hashEnv = new Hashtable();
        hashEnv.put("java.naming.provider.url", AdServer);
        hashEnv.put("java.naming.security.principal", UserName);
        hashEnv.put("java.naming.security.credentials", Password);
        hashEnv.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");

        try {
            dirContext = new InitialDirContext(hashEnv);
            boolean var5 = true;
            return var5;
        } catch (Exception var15) {
            var15.printStackTrace();
        } finally {
            if (null != dirContext) {
                try {
                    dirContext.close();
                    dirContext = null;
                } catch (Exception var14) {
                    var14.printStackTrace();
                }
            }

        }

        return false;
    }
}



